//
// Created by jack on 2021/2/1.
//

#include "weilapb_defines.h"

#include <WL.Service.pb.h>
#include <pb_decode.h>
#include <string.h>

#include "weilapb_datafuns.h"

#include "weilapb.h"
#include "weilapb_error.h"
#include "weilapb_friend.h"
#include "weilapb_group.h"
#include "weilapb_internal.h"
#include "weilapb_location.h"
#include "weilapb_loginmsg.h"
#include "weilapb_sessionmsg.h"
#include "weilapb_system.h"
#include "weilapb_user.h"

#ifdef DEBUG_MEM
#    include <stdio.h>
#endif

WeilaCtx* pWeilaCtx = PB_NULL;

#define RECV_BUFFER_SIZE (8 * 1024)
#define MAX_RECV_BUFFER_SIZE (32 * 1024)

#define BUILD_UINT32_BE(BUF, OFFSET)                                                                                   \
    ((((PB_UINT32)BUF[OFFSET]) << 24) | (((PB_UINT32)BUF[OFFSET + 1]) << 16) | (((PB_UINT32)BUF[OFFSET + 2]) << 8)     \
     | BUF[OFFSET + 3])

#define BUILD_UINT16_BE(BUF, OFFSET) ((((PB_UINT16)BUF[OFFSET]) << 8) | ((PB_UINT16)BUF[OFFSET + 1]))

#define WRITE_UINT32_BE(VALUE, BUF, OFFSET)                                                                            \
    do {                                                                                                               \
        BUF[OFFSET]     = (PB_UINT8)(((PB_UINT32)(VALUE & 0xFF000000)) >> 24);                                         \
        BUF[OFFSET + 1] = (PB_UINT8)(((PB_UINT32)(VALUE & 0x00FF0000)) >> 16);                                         \
        BUF[OFFSET + 2] = (PB_UINT8)(((PB_UINT32)(VALUE & 0x0000FF00)) >> 8);                                          \
        BUF[OFFSET + 3] = (PB_UINT8)(VALUE & 0x000000FF);                                                              \
        OFFSET += 4;                                                                                                   \
    } while (0);

#define WRITE_UINT16_BE(VALUE, BUF, OFFSET)                                                                            \
    do {                                                                                                               \
        BUF[OFFSET]     = (((PB_UINT16)(VALUE & 0xFF00)) >> 8);                                                        \
        BUF[OFFSET + 1] = (VALUE & 0x00FF);                                                                            \
        OFFSET += 2;                                                                                                   \
    } while (0);

void* weilapb_alloc(PB_UINT32 size, PB_CHAR* filename, PB_INT32 line) {
    if (pWeilaCtx) {
        void* ptr = pWeilaCtx->pbFunHook.allocMem(size);
        if (ptr) {
            memset(ptr, 0, size);
#ifdef DEBUG_MEM
            PB_UINT32 i;
            for (i = 0; i < 1024; i++) {
                if (!pWeilaCtx->memInfoLink[i].valid) {
                    break;
                }
            }

            if (i < 1024) {
                if (pWeilaCtx->maxMemInfo.memSize < size) {
                    pWeilaCtx->maxMemInfo.memSize    = size;
                    pWeilaCtx->maxMemInfo.pFilename  = filename;
                    pWeilaCtx->maxMemInfo.lineNumber = line;
                }
                pWeilaCtx->memInfoLink[i].valid      = 1;
                pWeilaCtx->memInfoLink[i].pFilename  = filename;
                pWeilaCtx->memInfoLink[i].lineNumber = line;
                pWeilaCtx->memInfoLink[i].pPtr       = ptr;
                pWeilaCtx->memInfoLink[i].memSize    = size;
            }
#endif
        }
        return ptr;
    }

    return PB_NULL;
}

void weilapb_free(void* ptr, char* filename, int line) {
    if (pWeilaCtx) {
        pWeilaCtx->pbFunHook.freeMem(ptr);
#ifdef DEBUG_MEM
        PB_UINT32 i;
        for (i = 0; i < 1024; i++) {
            if (pWeilaCtx->memInfoLink[i].pPtr == ptr) {
                break;
            }
        }

        if (i < 1024) {
            pWeilaCtx->memInfoLink[i].valid      = 0;
            pWeilaCtx->memInfoLink[i].pFilename  = PB_NULL;
            pWeilaCtx->memInfoLink[i].lineNumber = 0;
            pWeilaCtx->memInfoLink[i].pPtr       = PB_NULL;
            pWeilaCtx->memInfoLink[i].memSize    = 0;
        }
#endif
    }
}
#ifdef DEBUG_MEM
void weilapb_printMemInfo() {
    PB_UINT32 i;
    WL_LOG("Max Memory Size:%d\n", pWeilaCtx->maxMemInfo.memSize);
    WL_LOG("Max Memory filename:%s\n", pWeilaCtx->maxMemInfo.pFilename);
    WL_LOG("Max Memory line:%d\n", pWeilaCtx->maxMemInfo.lineNumber);
    for (i = 0; i < 1024; i++) {
        if (pWeilaCtx->memInfoLink[i].valid) {
            WL_LOG("MEM: %p\n", pWeilaCtx->memInfoLink[i].pPtr);
            WL_LOG("\tSIZE: %d\n", pWeilaCtx->memInfoLink[i].memSize);
            WL_LOG("\tFile: %s\n", pWeilaCtx->memInfoLink[i].pFilename);
            WL_LOG("\tLine: %d\n", pWeilaCtx->memInfoLink[i].lineNumber);
        }
    }
}
#endif

PB_BOOL weilapb_init(const PBFunHook* pPbFunHook) {
    if (pPbFunHook && pPbFunHook->allocMem && pPbFunHook->freeMem && pPbFunHook->getTimeStamp) {
        pWeilaCtx = (WeilaCtx*)pPbFunHook->allocMem(sizeof(WeilaCtx));
        memset(pWeilaCtx, 0, sizeof(WeilaCtx));
        memcpy(&pWeilaCtx->pbFunHook, pPbFunHook, sizeof(PBFunHook));
        pWeilaCtx->pRecvBuffer = PB_ALLOC(RECV_BUFFER_SIZE);
        if (pWeilaCtx->pRecvBuffer) {
            pWeilaCtx->bufferSize = RECV_BUFFER_SIZE;
            return PB_TRUE;
        } else {
            pWeilaCtx->bufferSize = 0;
        }
    }

    return PB_FALSE;
}

void weilapb_setDeviceConfig(PB_CHAR* pAppId, PB_CHAR* pAppKey, PB_CHAR* pSpecial, PB_CHAR* pDevVersion) {
    if (pWeilaCtx) {
        PB_UINT32 len       = 0;
        pWeilaCtx->recvSize = 0;  //重置,否则用户重新登录可能导致缓存区数据出错
        if (pAppId) {
            len = strlen(pAppId);
            memset(pWeilaCtx->appId, 0, MAX_PHONE_NUM_LEN);
            strncpy(pWeilaCtx->appId, pAppId, len < MAX_PHONE_NUM_LEN ? len : (MAX_PHONE_NUM_LEN - 1));
        }

        if (pAppKey) {
            len = strlen(pAppKey);
            memset(pWeilaCtx->appKey, 0, MAX_SHORT_STRING_LEN);
            strncpy(pWeilaCtx->appKey, pAppKey, len < MAX_SHORT_STRING_LEN ? len : (MAX_SHORT_STRING_LEN - 1));
        }

        if (pSpecial) {
            len = strlen(pSpecial);
            memset(pWeilaCtx->deviceSpecial, 0, MAX_NORMAL_STRING_LEN);
            strncpy(
                pWeilaCtx->deviceSpecial, pSpecial, len < MAX_NORMAL_STRING_LEN ? len : (MAX_NORMAL_STRING_LEN - 1));
        }

        if (pDevVersion) {
            len = strlen(pDevVersion);
            memset(pWeilaCtx->deviceInfo, 0, MAX_URL_STRING_LEN);
            strncpy(pWeilaCtx->deviceInfo, pDevVersion, len < MAX_URL_STRING_LEN ? len : (MAX_URL_STRING_LEN - 1));
        }
    }
}

void weilapb_registerListener(PB_EVENT_LISTENER pbEventListener) {
    if (pWeilaCtx) {
        pWeilaCtx->listener = pbEventListener;
    }
}

/**
 * 对收到的网络数据进行解析，如果数据不足则返回错误。如果读取的数据有异样，就抛弃此数据
 * @param pData
 * @param dataSize
 * @return
 */
WeilaMsgHeader* weilapb_decodeMsgHeader(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WeilaMsgHeader* pWeilaMsgHeader = PB_NULL;
    PB_UINT32       offset          = 0;

    if (dataSize < WEILA_MESSAGE_HEADER_LENGTH) {
        return PB_NULL;
    }

    pWeilaMsgHeader = (WeilaMsgHeader*)PB_ALLOC(sizeof(WeilaMsgHeader));

    if (pWeilaMsgHeader) {
        pWeilaMsgHeader->length = BUILD_UINT32_BE(pData, offset);
        offset += 4;
        pWeilaMsgHeader->version = BUILD_UINT16_BE(pData, offset);
        offset += 2;
        pWeilaMsgHeader->flag = BUILD_UINT16_BE(pData, offset);
        offset += 2;
        pWeilaMsgHeader->serviceId = BUILD_UINT16_BE(pData, offset);
        offset += 2;
        pWeilaMsgHeader->commandId = BUILD_UINT16_BE(pData, offset);
        offset += 2;
        pWeilaMsgHeader->seq = BUILD_UINT16_BE(pData, offset);
        offset += 2;
        pWeilaMsgHeader->reserved = BUILD_UINT16_BE(pData, offset);
        offset += 2;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate memory for msg header fail");
    }

    return pWeilaMsgHeader;
}

void weilapb_encodeWeilaMsgHeader(WeilaMsgHeader* pWeilaMsgHeader, PB_UINT8* pBuffer) {
    PB_UINT32 offset       = 0;
    PB_UINT16 mixCommandId = ((PB_UINT16)(pWeilaMsgHeader->serviceId << 8) | pWeilaMsgHeader->commandId);
    WRITE_UINT32_BE(pWeilaMsgHeader->length, pBuffer, offset);
    WRITE_UINT16_BE(pWeilaMsgHeader->version, pBuffer, offset);
    WRITE_UINT16_BE(pWeilaMsgHeader->flag, pBuffer, offset);
    WRITE_UINT16_BE(15, pBuffer, offset);            // service id必须是15, 新协议
    WRITE_UINT16_BE(mixCommandId, pBuffer, offset);  // command id和service id合并
    WRITE_UINT16_BE(pWeilaMsgHeader->seq, pBuffer, offset);
    WRITE_UINT16_BE(0, pBuffer, offset);
}

PBWeilaMsg* weilapb_processWeilaMsg(const PB_UINT8* pData, PB_UINT32 dataSize) {
    PBWeilaMsg*               pWeilaMsg = PB_NULL;
    pb_istream_t              istream;
    PB_INT32                  commandId, commandType;
    WL_Service_ServiceMessage wlServiceServiceMessage = WL_Service_ServiceMessage_init_zero;
    istream                                           = pb_istream_from_buffer(pData, dataSize);
    if (!pb_decode(&istream, WL_Service_ServiceMessage_fields, &wlServiceServiceMessage)) {
        weilapb_error(ERR_DECODE, "decode service msg failed dataSize %d", dataSize);
        return PB_NULL;
    }

    commandId   = wlServiceServiceMessage.serviceHead.commandId;
    commandType = wlServiceServiceMessage.serviceHead.commandType;

    /*if (wlServiceServiceMessage.serviceHead.has_resultCode) {
        if (wlServiceServiceMessage.serviceHead.resultCode != 0) {
            pWeilaMsg              = (PBWeilaMsg*)PB_ALLOC(sizeof(PBWeilaMsg));
            pWeilaMsg->commandId   = commandId;
            pWeilaMsg->commandType = commandType;
            pWeilaMsg->resultCode  = wlServiceServiceMessage.serviceHead.resultCode;
            pWeilaMsg->seqNum      = wlServiceServiceMessage.serviceHead.seq;
            pWeilaMsg->serviceId   = wlServiceServiceMessage.serviceHead.serviceId;
            pWeilaMsg->message     = WL_ERROR_MSG;
            return pWeilaMsg;
        }
    }*/

    switch (wlServiceServiceMessage.serviceHead.serviceId) {
        case WL_Service_ServiceID_SERVICE_LOGIN: {
            pWeilaMsg = weilapb_decodeLoginMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_SESSION: {
            pWeilaMsg = weilapb_decodeSessionMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_GROUP: {
            pWeilaMsg = weilapb_decodeGroupMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_FRIEND: {
            pWeilaMsg = weilapb_decodeFriendMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_USER: {
            pWeilaMsg = weilapb_decodeUserMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_SYSTEM: {
            pWeilaMsg = weilapb_decodeSystemMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_LOCATION: {
            pWeilaMsg = weilapb_decodeLocationMsg(commandId, commandType, pData, dataSize);
        } break;

        case WL_Service_ServiceID_SERVICE_BUSINESS: {
        } break;
    }

    return pWeilaMsg;
}

static bool weilapb_reallocRecvBuf(PB_UINT32 newSize) {
    if (pWeilaCtx) {
        PB_UINT8* newBuf = (PB_UINT8*)PB_ALLOC(newSize);
        if (newBuf) {
            pWeilaCtx->bufferSize = newSize;
            memcpy(newBuf, pWeilaCtx->pRecvBuffer, pWeilaCtx->recvSize);
            PB_FREE(pWeilaCtx->pRecvBuffer);
            pWeilaCtx->pRecvBuffer = newBuf;

            return PB_TRUE;
        }
    }

    return PB_FALSE;
}

void weilapb_reset_feedData(void) {
    if (pWeilaCtx) {
        pWeilaCtx->recvSize   = 0;  //重置,否则用户重新登录可能导致缓存区数据出错
        pWeilaCtx->packageLen = 0;
        pWeilaCtx->leftLen    = 0;
    }
}

void weilapb_feedData(PB_UINT8* pData, PB_INT32 uDataSize) {
    WeilaMsgHeader* pWeilaMsgHeader = PB_NULL;
    PBWeilaMsg*     pPbWeilaMsg     = PB_NULL;

    if (pWeilaCtx && pWeilaCtx->bufferSize > 0) {
        if (uDataSize > pWeilaCtx->bufferSize - pWeilaCtx->recvSize && pWeilaCtx->bufferSize < MAX_RECV_BUFFER_SIZE) {
            if (!weilapb_reallocRecvBuf(MAX_RECV_BUFFER_SIZE)) {
                PBEvent pbEvent;
                pWeilaCtx->recvSize = 0;
                weilapb_error(ERR_INVALID_RECV_DATA, "weilapb_feedData malloc recv buffer fail");
                pbEvent.pData     = NULL;
                pbEvent.eventType = PB_EVT_SYSTEM_ERR;
                pWeilaCtx->listener(&pbEvent);
                return;
            }
        }
        //数据包过大丢弃
        if (pWeilaCtx->packageLen > pWeilaCtx->bufferSize) {
            pWeilaCtx->recvSize = 0;
            //长度超限,非法数据,断开连接
            if (pWeilaCtx->packageLen > 204800 /*MAX_RECV_BUFFER_SIZE * 2*/) {
                PBEvent pbEvent;
                weilapb_error(ERR_INVALID_RECV_DATA,
                              "weilapb_feedData invalid data packageLen %d bufferSize %d",
                              pWeilaCtx->packageLen,
                              pWeilaCtx->bufferSize);
                pbEvent.pData     = NULL;
                pbEvent.eventType = PB_EVT_SYSTEM_ERR;
                pWeilaCtx->listener(&pbEvent);
                return;
            }
            //数据丢弃
            if (pWeilaCtx->leftLen > uDataSize) {
                pWeilaCtx->leftLen -= uDataSize;
                return;
            }
            //超大数据包接收完
            else {
                if (pWeilaCtx->leftLen < uDataSize) {
                    memcpy(&pWeilaCtx->pRecvBuffer[0], pData + pWeilaCtx->leftLen, uDataSize - pWeilaCtx->leftLen);
                }
                pWeilaCtx->recvSize   = uDataSize - pWeilaCtx->leftLen;
                pWeilaCtx->leftLen    = 0;
                pWeilaCtx->packageLen = 0;
            }
        } else {
            if (pWeilaCtx->recvSize + uDataSize <= pWeilaCtx->bufferSize) {
                memcpy(&pWeilaCtx->pRecvBuffer[pWeilaCtx->recvSize], pData, uDataSize);
                pWeilaCtx->recvSize += uDataSize;
            } else {
                //两个数据包连接且长度超过缓存区,断开连接重连
                PBEvent pbEvent;
                weilapb_error(ERR_INVALID_RECV_DATA,
                              "weilapb_feedData drop recvSize %d uDataSize %d packageLen %d leftLen %d",
                              pWeilaCtx->recvSize,
                              uDataSize,
                              pWeilaCtx->packageLen,
                              pWeilaCtx->leftLen);
                pWeilaCtx->recvSize = 0;
                pbEvent.pData       = NULL;
                pbEvent.eventType   = PB_EVT_SYSTEM_ERR;
                pWeilaCtx->listener(&pbEvent);
                return;
            }
        }

        while (pWeilaCtx->recvSize) {
            pWeilaMsgHeader = weilapb_decodeMsgHeader(pWeilaCtx->pRecvBuffer, pWeilaCtx->recvSize);
            if (pWeilaMsgHeader) {
                PB_UINT32 msgContentSize;
                pWeilaCtx->packageLen = pWeilaMsgHeader->length;
                pWeilaCtx->leftLen    = 0;
                //超大数据包
                if (pWeilaMsgHeader->length > pWeilaCtx->bufferSize) {
                    weilapb_error(ERR_INVALID_RECV_DATA,
                                  "weilapb_feedData with large data len %d version %d serviceId %d commandId %d",
                                  pWeilaMsgHeader->length,
                                  pWeilaMsgHeader->version,
                                  pWeilaMsgHeader->serviceId,
                                  pWeilaMsgHeader->commandId);
                    weilapb_error(ERR_INVALID_RECV_DATA,
                                  "weilapb_feedData with large recvSize %d uDataSize %d packageLen %d leftLen %d",
                                  pWeilaCtx->recvSize,
                                  uDataSize,
                                  pWeilaCtx->packageLen,
                                  pWeilaCtx->leftLen);
                    if (15 == pWeilaMsgHeader->serviceId
                        && pWeilaCtx->packageLen < 204800 /*MAX_RECV_BUFFER_SIZE * 2*/) {
                        pWeilaCtx->leftLen  = pWeilaCtx->packageLen - pWeilaCtx->recvSize;
                        pWeilaCtx->recvSize = 0;
                    }
                    //非法数据
                    else {
                        PBEvent pbEvent;
                        weilapb_error(ERR_INVALID_RECV_DATA,
                                      "weilapb_feedData invalid data packageLen %d bufferSize %d",
                                      pWeilaCtx->packageLen,
                                      pWeilaCtx->bufferSize);
                        pbEvent.pData     = NULL;
                        pbEvent.eventType = PB_EVT_SYSTEM_ERR;
                        pWeilaCtx->listener(&pbEvent);
                    }
                    PB_FREE(pWeilaMsgHeader);
                    return;
                }
                msgContentSize = pWeilaMsgHeader->length;
                if (msgContentSize <= pWeilaCtx->recvSize) {
                    PB_UINT8* pContent = (PB_UINT8*)(pWeilaCtx->pRecvBuffer + WEILA_MESSAGE_HEADER_LENGTH);
                    PBEvent   pbEvent;

                    if (15 == pWeilaMsgHeader->serviceId) {
                        pPbWeilaMsg = weilapb_processWeilaMsg(pContent, msgContentSize - WEILA_MESSAGE_HEADER_LENGTH);
                        if (pPbWeilaMsg) {
                            pPbWeilaMsg->seqNum = pWeilaMsgHeader->seq;
                            pbEvent.pData       = pPbWeilaMsg;
                            switch (pPbWeilaMsg->commandType) {
                                case WL_Service_CommandType_COMMAND_NOTIFY: {
                                    pbEvent.eventType = PB_EVT_MSG_IND;
                                    if (pPbWeilaMsg->serviceId == WL_Service_ServiceID_SERVICE_SESSION
                                        && pPbWeilaMsg->commandId
                                               == WL_Session_SessionCommandId_SESSION_COMMAND_MSGDATA) {
                                        pbEvent.eventType = PB_EVT_SESSION_MSG_IND;
                                    }
                                } break;

                                case WL_Service_CommandType_COMMAND_RESPONSE: {
                                    pbEvent.eventType = PB_EVT_MSG_RSP;
                                } break;

                                case WL_Service_CommandType_COMMAND_REQUEST: {
                                    pbEvent.eventType = PB_EVT_MSG_REQ;
                                } break;
                            }

                            pWeilaCtx->listener(&pbEvent);
                        } else {
                            weilapb_error(ERR_INVALID_RECV_DATA,
                                          "weilapb_feedData parse fail protocol data len %d version %d serviceId %d "
                                          "commandId %d",
                                          pWeilaMsgHeader->length,
                                          pWeilaMsgHeader->version,
                                          pWeilaMsgHeader->serviceId,
                                          pWeilaMsgHeader->commandId);
                        }
                    } else {
                        weilapb_error(
                            ERR_INVALID_RECV_DATA,
                            "weilapb_feedData not support protocol data len %d version %d serviceId %d commandId %d",
                            pWeilaMsgHeader->length,
                            pWeilaMsgHeader->version,
                            pWeilaMsgHeader->serviceId,
                            pWeilaMsgHeader->commandId);
                    }
                    pWeilaCtx->recvSize -= msgContentSize;
                    memmove(pWeilaCtx->pRecvBuffer, &pWeilaCtx->pRecvBuffer[msgContentSize], pWeilaCtx->recvSize);
                    if (pWeilaCtx->bufferSize != RECV_BUFFER_SIZE && pWeilaCtx->recvSize < RECV_BUFFER_SIZE) {
                        if (!weilapb_reallocRecvBuf(RECV_BUFFER_SIZE)) {
                            weilapb_error(ERR_OUT_OF_MEMORY, "allocate buffer of size:%d\n", RECV_BUFFER_SIZE);
                            PB_FREE(pWeilaMsgHeader);
                            return;
                        }
                    }
                    PB_FREE(pWeilaMsgHeader);
                } else {
                    PB_FREE(pWeilaMsgHeader);
                    break;
                }
            } else {
                break;
            }
        }
    }
}

void weilapb_releasePBEncResult(PBEncResult* pPbEncResult) {
    if (pPbEncResult->errCode == ERR_NONE) {
        PB_FREE(pPbEncResult->pEncodedData);
    }
#ifdef DEBUG_MEM
    // weilapb_printMemInfo();
#endif
}

void weilapb_releasePBWeilaMsg(PBWeilaMsg* pPbWeilaMsg) {
    if (pPbWeilaMsg) {
        PB_UINT32 i;
        for (i = 0; i < pPbWeilaMsg->recyclePtrCount; i++) {
            if (pPbWeilaMsg->recyclePtrData[i].pointerType == RECYCLE_PTR_LINK) {
                weilapb_freePBLinkList(pPbWeilaMsg->recyclePtrData[i].pPtr);
            } else {
                weilapb_freeMsgDataLink(pPbWeilaMsg->recyclePtrData[i].pPtr);
            }
        }
        PB_FREE(pPbWeilaMsg);
    }
#ifdef DEBUG_MEM
    // weilapb_printMemInfo();
#endif
}

const ServiceCommandMessageMap messageMaps[] = {
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_LOGIN_APP),
     WL_LOGIN_LOGIN_MSG},  //对应的是PBRspLogin消息结构
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_LOGOUT),
     WL_LOGIN_LOGOUT_MSG},  //没有响应结果数据，只有消息结果
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_KICKOUT),
     WL_LOGIN_KICKOUT_MSG},  // 对应的是PB_UINT32数据，代表被踢的原因 0 封号， 1 同一类型客户端同时登录 2 被移动端踢掉
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_HEARTBEAT),
     WL_LOGIN_HEARTBEAT_MSG},  //没有响应结果数据，只有消息结果
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_ANSWER_BIND_EXTENSION),
     WL_LOGIN_ANSWER_BIND_EXTENSION_MSG},  // 对应PBRspAnswerBindExtension消息结构
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_BIND_EXTENSION),
     WL_LOGIN_BIND_EXTENSION_MSG},  // 通知对应PBNtfBindExtension， 响应只是返回消息结果
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_UNBIND_EXTENSION),
     WL_LOGIN_UNBIND_EXTENSION_MSG},  //没有响应结果数据，只有消息结果
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_LOCK_EXTENSION),
     WL_LOGIN_LOCK_EXTENSION},  // 通知设备状态 extensionState  0 未绑定， 1 绑定中， 2 已绑定， 3 上锁
    {ID(WL_Service_ServiceID_SERVICE_LOGIN, WL_Login_LoginCommandId_LOGIN_COMMAND_UNLOCK_EXTENSION),
     WL_LOGIN_UNLOCK_EXTENSION},  // 通知设备状态 extensionState  0 未绑定， 1 绑定中， 2 已绑定， 3 上锁
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_MSGDATA),
     WL_SESSION_MSGDATA_MSG},  // 通知为PBMsgData结构， 操作响应为PBSendMsgRsp
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_GET_MSG),
     WL_SESSION_GET_MSG_MSG},  // 操作响应为PBLinkList链表， 链表的具体数据为PBMsgData
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_READ_MSG),
     WL_SESSION_READ_MSG_MSG},  //没有响应结果数据，只有消息结果
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_GET_SESSION),
     WL_SESSION_GET_SESSION_MSG},  // 操作响应为PBGetSessionRsp数据， 里面的链表的具体数据为PBSessionInfo
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_REMOVE_SESSION),
     WL_SESSION_REMOVE_SESSION_MSG},  //没有响应结果数据，只有消息结果
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_GET_UNREAD_MSG),
     WL_SESSION_GET_UNREAD_MSG_MSG},  // 操作响应为PBLinkList链表， 链表的具体数据为PBMsgData
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_COMMAND_BURST_CONTROL),
     WL_SESSION_BURST_CTRL_MSG},  // 操作响应为PB_UINT32 duration， 持续时间， 通知消息为PBBurstCtlNtf数据
    {ID(WL_Service_ServiceID_SERVICE_SESSION, WL_Session_SessionCommandId_SESSION_EMBEDDED_COMMAND_ATTACH_SESSION),
     WL_SESSION_EMBEDDED_ATTACH_MSG},  // 附着会话响应结果，无数据，只有结果
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_GROUPVERSION),
     WL_GROUP_GET_GROUP_VER_MSG},  // 操作响应为PBLinkList链表，具体的数据为PBGroupSimpleInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_GROUPATTRIBUTE),
     WL_GROUP_GET_GROUP_ATTR_MSG},  // 操作响应为PBLinkList链表，具体数据为PBGroupAttr
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_CREATE_GROUP),
     WL_GROUP_CREATE_GROUP_MSG},  // 操作响应为PBCreateGroupRsp， 里面的链表数据为PBMemberInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_DELETE_GROUP),
     WL_GROUP_DEL_GROUP_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PB_UINT64，代表群id
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_DELETE_MEMBER),
     WL_GROUP_DEL_MEMBER_MSG},  // 操作响应无数据，只有操作结果，通知消息为PBDelMemberNtf
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_MEMBER_USERINFO),
     WL_GROUP_GET_MEMBER_USER_INFO_MSG},  // 操作响应为PBLinkList链表，具体数据为PBUserInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_ONLINE_MEMBER),
     WL_GROUP_GET_ONLINE_MEMBER_MSG},  // 操作响应为PBArray， 每一项为PB_UINT32
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_CHANGE_GROUPATTRIBUTE),
     WL_GROUP_CHANGE_GROUP_ATTR_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBGroupAttr
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_GROUPINFO),
     WL_GROUP_GET_GROUP_INFO_MSG},  // 操作响应为PBGroupInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GET_BLACKLIST),
     WL_GROUP_GET_BLACKLIST_MSG},  // 操作响应为PBLinkList链表，具体数据为PBUserInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_CHANGE_BLACKLIST),
     WL_GROUP_CHANGE_BLACKLIST_MSG},  // 操作响应无数据，只有成功结果
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_CHANGE_MEMBERINFO),
     WL_GROUP_CHANGE_MEMBER_INFO_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBMemberChangeNtf
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_ANSWER_GROUP_INVITE),
     WL_GROUP_ANSWER_GROUP_INVITE_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBAnswerGroupInviteNtf
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_GROUP_JOIN),
     WL_GROUP_GROUP_JOIN_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBGroupJoinNtf
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_ANSWER_GROUP_JOIN),
     WL_GROUP_ANSWER_GROUP_JOIN_MSG},  // 作响应无数据，只有成功结果， 通知消息数据为PBAnswerGroupJoinNtf
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_BROADCAST),
     WL_GROUP_BROADCAST_MSG},  // 作响应无数据，只有成功结果， 通知消息数据为PBLinkList}, 数据项为PBBroadcastInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_EMBEDDED_COMMAND_GET_GROUPVERSION),
     WL_GROUP_GET_EMBEDDED_GROUP_VER_MSG},  // 作为获取嵌入式群信息的相应数据，操作响应为PBLinkList链表，具体的数据为PBGroupSimpleInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_EMBEDDED_COMMAND_GET_GROUPINFO),
     WL_GROUP_GET_EMBEDDED_INFOS},  // 作为获取嵌入式群信息的相应数据，消息为PBLinkList，数据项为PBEmbeddedGroupInfo
    {ID(WL_Service_ServiceID_SERVICE_GROUP, WL_Group_GroupCommandId_GROUP_COMMAND_NEW_MEMBER),
     WL_GROUP_NEW_MEMBER_NTF_MSG},  // 群组新成员通知消息，对应的数据结构为PBNewMemberNtf
    {ID(WL_Service_ServiceID_SERVICE_USER, WL_User_UserCommandId_USER_COMMAND_CHANGE_USERINFO),
     WL_USER_CHANGE_USER_INFO_MSG},  // 作响应无数据，只有成功结果
    {ID(WL_Service_ServiceID_SERVICE_USER, WL_User_UserCommandId_USER_COMMAND_SET_CONFIG),
     WL_USER_SET_CONFIG_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为MAX_LONG_STRING_LEN长度的字符串缓存
    {ID(WL_Service_ServiceID_SERVICE_USER, WL_User_UserCommandId_USER_COMMAND_GET_CONFIG),
     WL_USER_GET_CONFIG_MSG},  // 操作响应为MAX_LONG_STRING_LEN长度的字符串缓存
    {ID(WL_Service_ServiceID_SERVICE_LOCATION, WL_Location_LocationCommandId_LOCATION_COMMAND_REPORT_LOCATION),
     WL_LOCATION_REPORT_LOCATION_MSG},  // 作响应无数据，只有成功结果
    {ID(WL_Service_ServiceID_SERVICE_LOCATION, WL_Location_LocationCommandId_LOCATION_COMMAND_GET_LOCATION),
     WL_LOCATION_GET_LOCATION_MSG},  // 操作响应为PBGetLocationRsp
    {ID(WL_Service_ServiceID_SERVICE_LOCATION, WL_Location_LocationCommandId_LOCATION_COMMAND_LOCATION_CONTROL),
     WL_LOCATION_LOCATION_CONTROL_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBLocationCtrlNtf
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIENDINFO),
     WL_FRIEND_GET_FRIEND_INFO_MSG},  // 操作响应PBGetFriendInfoRsp}, 其中有两个链表，对应PBUserInfo 和 对应PBFriendInfo
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIEND_USERINFO),
     WL_FRIEND_GET_FRIEND_USER_INFO_MSG},  // 操作响应为PBLinkList链表，具体数据为PBUserInfo
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIEND_INVITEINFO),
     WL_FRIEND_GET_FRIEND_INVITE_INFO_MSG},  //操作响应PBGetFriendInviteInfoRsp},其中有两个链表，对应PBUserInfo 和
                                             //对应PBFriendInfo
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_FRIEND_INVITE),
     WL_FRIEND_FRIEND_INVITE_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBAnswerFriendInviteNtf
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_ANSWER_FRIEND_INVITE),
     WL_FRIEND_ANSWER_FRIEND_INVITE_MSG},  // 操作响应无数据，只有成功结果， 通知消息数据为PBAnswerFriendInviteNtf
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_NEW_FRIEND),
     WL_FRIEND_NEW_FRIEND_MSG},  //通知消息数据为PBFriendInfo
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_DELETE_FRIEND),
     WL_FRIEND_DELETE_FRIEND_MSG},  //操作响应无数据，只有成功结果， 通知消息数据为PB_UINT32 代表用户id
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_CHANGE_FRIENDINFO),
     WL_FRIEND_CHANGE_FRIEND_INFO_MSG},  // 操作响应无数据，只有成功结果
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_BLACKLIST),
     WL_FRIEND_GET_BLACKLIST_MSG},  // 操作响应为PBLinkList链表，具体数据为PBUserInfo
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_CHANGE_BLACKLIST),
     WL_FRIEND_CHANGE_BLACKLIST_MSG},  // 操作响应无数据，只有成功结果
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_ONLINE_FRIEND),
     WL_FRIEND_GET_ONLINE_FRIEND_MSG},  // 操作响应为PBArray， 每一项为PB_UINT32
    {ID(WL_Service_ServiceID_SERVICE_FRIEND, WL_Friend_FriendCommandId_FRIEND_EMBEDDED_COMMAND_GET_FRIENDINFO),
     WL_FRIEND_GET_EMBEDDED_FRIEND_INFOS},  // 操作响应为PBLinkList链表，具体数据为PBFriendEmbeddedInfo
    {ID(WL_Service_ServiceID_SERVICE_SYSTEM, WL_System_SystemCommandId_SYSTEM_COMMAND_NOTIFICATION),
     WL_SYSTEM_NOTIFICATION_MSG},  // 操作响应为PBString
};

PB_UINT32 weilapb_getMessageByCommandId(PB_UINT16 serviceId, PB_UINT16 commandId) {
    PB_UINT32 id    = ID(serviceId, commandId);
    PB_INT32  i     = 0;
    PB_INT32  count = sizeof(messageMaps) / sizeof(ServiceCommandMessageMap);

    for (i = 0; i < count; i++) {
        if (messageMaps[i].id == id) {
            return messageMaps[i].message;
        }
    }

    return WL_ERROR_MSG;
}
